#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>




#define CNT_BATTERY (2)

struct vol_2_per {
	int voltage;
	int percent;
};

struct misc_batt_data {
	char name[16];
	int voltage;
	int status;
	int percent;
	struct vol_2_per *v2p_table;
};


static ssize_t name_show(
    struct device *dev,
    struct device_attribute *attr,
    char *buf)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;

	return snprintf(buf, PAGE_SIZE, "%s\n", pdata->name);
}

static ssize_t battery_voltage_show(
    struct device *dev,
    struct device_attribute *attr,
    char *buf)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;

	return snprintf(buf, PAGE_SIZE, "%d\n", pdata->voltage);
}
static ssize_t battery_voltage_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;
	char *after;

	pdata->voltage = simple_strtoul(buf, &after, 10);
	return count;
}

// 电压与百分比转换表，需要后期修改
struct vol_2_per vol_2_per_list[] = {
	{8055, 100},
	{8000, 80},
	{7730, 60},
	{7405, 40},
	{7050, 30},
	{6500, 20},
	{4, 1},
	{0, 0},
};

static ssize_t battery_percent_show(
    struct device *dev,
    struct device_attribute *attr,
    char *buf)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;
	struct vol_2_per *tlist   = vol_2_per_list;
	int               percent = 0;

	do {
		if (tlist->voltage <= pdata->voltage) {
			break;
		}
		tlist++;
	}while (tlist->voltage != 0) ;
	percent = tlist->percent;
	return snprintf(buf, PAGE_SIZE, "%d\n", percent);
}


static ssize_t battery_status_show(
    struct device *dev,
    struct device_attribute *attr,
    char *buf)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;

	return snprintf(buf, PAGE_SIZE, "%s\n", pdata->status ? "charging" : "using");
}
static ssize_t battery_status_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
	struct misc_batt_data *pdata = (struct misc_batt_data *)dev->platform_data;
	char *after;

	pdata->status = simple_strtoul(buf, &after, 10);
	return count;
}


static DEVICE_ATTR(
    name, S_IRUGO, name_show, NULL);
static DEVICE_ATTR(
    voltage, S_IWUSR | S_IRUGO, battery_voltage_show, battery_voltage_store);
static DEVICE_ATTR(
    percent, S_IRUGO, battery_percent_show, NULL);
static DEVICE_ATTR(
    status, S_IWUSR | S_IRUGO, battery_status_show, battery_status_store);
static struct miscdevice *pmisc;







int __init battery_init(void)
{
	int                    i;
	char                   name[16];
	struct device         *this_dev;
	struct miscdevice     *tpmisc;
	struct misc_batt_data *pdata, *tpdata;

	pmisc = kzalloc(sizeof(struct miscdevice) * CNT_BATTERY, GFP_KERNEL);
	pdata = kzalloc(sizeof(struct misc_batt_data) * CNT_BATTERY, GFP_KERNEL);

	tpmisc = pmisc, tpdata = pdata;
	for (i = 0; i < CNT_BATTERY; i++) {
		snprintf(name, sizeof(name), "battery%d", i);
		tpmisc->name  = name;
		tpmisc->minor = MISC_DYNAMIC_MINOR;
		tpmisc->fops  = NULL;
		misc_register(tpmisc);

		this_dev                = tpmisc->this_device;
		this_dev->platform_data = tpdata;

		tpdata->voltage         = 8055;     /* 默认8000mV */
		tpdata->status          = 0;        /* 没插入适配器 */
		tpdata->percent         = 100;      /* 100%电量 */
		strncpy(tpdata->name, name, sizeof(((struct misc_batt_data *)(0))->name));

		device_create_file(this_dev, &dev_attr_name);
		device_create_file(this_dev, &dev_attr_voltage);
		device_create_file(this_dev, &dev_attr_percent);
		device_create_file(this_dev, &dev_attr_status);
		tpmisc++, tpdata++;
	}
	return 0;
}

void __exit battery_exit(void)
{
	int i;
	struct miscdevice *tpmisc;

	if (pmisc) {
		tpmisc = pmisc;
		for (i = 0; i < CNT_BATTERY; i++) {
			misc_deregister(tpmisc);
			tpmisc++;
		}
		kfree(pmisc);
	}
}


#if 0
module_init(battery_init);
module_exit(battery_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("glink devices user space export");
#endif
